/**************************************************************************
*   Copyright (C) 2010 Chernov Dmitry                                     *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/

#ifndef MARBLETASK_H
#define MARBLETASK_H

#include "Marble.h"

#include <string>
#include <map>
#include <vector>

class MarbleGameSolver;


class MarbleTask
{
public:
    /*
     * First parameter is string with task to be solved
     * second is manager which runs tasks in parallel and collects result
     *
     */
    MarbleTask( const std::string& field, MarbleGameSolver* manager );

    /*
     * Default constructor
     *
     */
    MarbleTask();

    ~MarbleTask();

    /*
     * Load all the data needed for solving from string
     *
     */
    void loadFromString( const std::string& field );

    /*
     * Find solution(s) for this task, and store results
     * in given manager instance
     *
     */
    void solve();

private:
    /*
     * Manager which helps several instances of MarbleTask work together
     * e.g. in different threads
     *
     */
    MarbleGameSolver* m_manager;
    friend class MarbleGameSolver;

    /*
     * Storage for input data
     *
     */
    std::vector<Marble> m_marbles;
    std::map<int, Hole> m_holes;
    std::map<int, Wall> m_walls;

    /*
     * Direction where marbles gonna roll
     *
     */
    enum direction
    {
        none = 0,
        up = 1,
        right = 2,
        down = 3,
        left = 4,
    };

    /*
     * Result of a marble movement
     *
     */
    enum moveStatus
    {
        regular = 1,
        commit = 2,
        failure = 3,
        not_moved = 4,
    };

    /*
     * Parameters of a marble field
     *
     */
    bool m_initialized;
    int m_size;
    int m_sizeTotal;
    int m_noMarbles;
    int m_noWalls;

    /*
     * Parameters of search
     *
     */
    static const int MAX_DEPTH_DEFAULT = 12;
    int m_maxDepth;

    /*
     * To avoid waisting time producing many little subtasks
     * which only slow down the count
     *
     */
    static const int MIN_SUBTASK_DEPTH = 5;

    /*
     * Search state
     *
     */
    int m_depth;
    int m_positioned;
    direction m_dir;
    std::vector<direction> m_doneRolls;

    /*
     * Helper function for coordinate translation from x,y to one index
     *
     */
    int pointToIndex( int x, int y )
    {
        return x + m_size*y;
    }

    /*
     * Check if pass through cell at pos is enabled from direction dir
     *
     */
    bool isPassEnabled( int pos, direction dir );

    /*
     * Moves marble marbleNo from source cell to destination cell
     * turn is needed for undo later
     */
    moveStatus move( int turn, int marbleNo, int src_ind, int dst_ind );

    /*
     * When rolling board we need to iterate field in different order
     * depending on the direction of roll. This function gives next
     * cell index from current index depending on roll direction
     *
     */
    int getNextCellIndex( int cIndex, direction dir );

    /*
     * Rolls marbleNo marble from pos cell in dir direction
     * turn is needed for later undo
     *
     */
    moveStatus roll( int turn, int marbleNo, int pos, direction dir );

    /*
     * Storage for input data
     *
     */
    bool rollBoard( int turn, int& done, direction dir );

    /*
     * Storage for input data
     *
     */
    void unrollBoard( int turn );

    /*
     * Recursive solution finding function
     *
     */
    void innerFind( int depth, direction dir, int current_positioned );

    /*
     * Field lookup routines
     *
     */
    int getMarbleAtPos(int pos);
    bool isHolePresent(int pos);

    /*
     * Debug helping routine
     *
     */
    void showField();
};

#endif // MARBLETASK_H
